package find_way;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;

public class PathfindingVisualizer extends JFrame {
    private static final int GRID_SIZE = 20;
    private static final int CELL_SIZE = 30;
    private final JPanel gridPanel;
    private final JRadioButton aStarButton, bfsButton, dijkstraButton, jpsButton;
    private final JButton startButton, clearButton;
    private Cell[][] grid;
    private Point start, end;
    private boolean isSettingObstacles = false;

    public PathfindingVisualizer() {
        setTitle("Pathfinding Algorithm Visualizer");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        // 创建网格面板
        gridPanel = new JPanel(new GridLayout(GRID_SIZE, GRID_SIZE));
        gridPanel.setPreferredSize(new Dimension(GRID_SIZE * CELL_SIZE, GRID_SIZE * CELL_SIZE));
        initializeGrid();
        add(gridPanel, BorderLayout.CENTER);

        // 创建控制面板
        JPanel controlPanel = new JPanel();
        controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.Y_AXIS));
        controlPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

        // 创建算法选择按钮组
        ButtonGroup algorithmGroup = new ButtonGroup();
        aStarButton = new JRadioButton("A*");
        bfsButton = new JRadioButton("BFS");
        dijkstraButton = new JRadioButton("Dijkstra");
        jpsButton = new JRadioButton("JPS");

        algorithmGroup.add(aStarButton);
        algorithmGroup.add(bfsButton);
        algorithmGroup.add(dijkstraButton);
        algorithmGroup.add(jpsButton);

        aStarButton.setSelected(true); // 默认选择A*

        // 添加算法选择按钮到控制面板
        controlPanel.add(new JLabel("选择算法:"));
        controlPanel.add(aStarButton);
        controlPanel.add(bfsButton);
        controlPanel.add(dijkstraButton);
        controlPanel.add(jpsButton);

        // 添加按钮面板
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 5)); // 左对齐
        buttonPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
        startButton = new JButton("开始寻路");
        startButton.addActionListener(new StartButtonListener());

        clearButton = new JButton("清除障碍");
        clearButton.addActionListener(e -> clearObstacles());

        buttonPanel.add(startButton);
        buttonPanel.add(clearButton);

        controlPanel.add(Box.createVerticalStrut(10));
        controlPanel.add(buttonPanel);

        add(controlPanel, BorderLayout.EAST);

        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private void initializeGrid() {
        grid = new Cell[GRID_SIZE][GRID_SIZE];
        gridPanel.removeAll();

        for (int row = 0; row < GRID_SIZE; row++) {
            for (int col = 0; col < GRID_SIZE; col++) {
                grid[row][col] = new Cell(row, col);
                grid[row][col].addMouseListener(new CellMouseListener());
                gridPanel.add(grid[row][col]);
            }
        }

        // 设置起点和终点
        start = new Point(3, 3);
        end = new Point(15, 16);
        grid[start.x][start.y].setStart();
        grid[end.x][end.y].setEnd();
    }

    private void clearObstacles() {
        for (int row = 0; row < GRID_SIZE; row++) {
            for (int col = 0; col < GRID_SIZE; col++) {
                if (grid[row][col].isObstacle) {
                    grid[row][col].reset();
                    if (row == start.x && col == start.y) {
                        grid[row][col].setStart();
                    } else if (row == end.x && col == end.y) {
                        grid[row][col].setEnd();
                    }
                }
            }
        }
    }

    private class StartButtonListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            // 重置网格（除了障碍物、起点和终点）
            for (int row = 0; row < GRID_SIZE; row++) {
                for (int col = 0; col < GRID_SIZE; col++) {
                    if (!grid[row][col].isObstacle && !grid[row][col].isStart && !grid[row][col].isEnd) {
                        grid[row][col].reset();
                    }
                }
            }

            // 根据选择的算法执行寻路
            if (aStarButton.isSelected()) {
                executeAStar();
            } else if (bfsButton.isSelected()) {
                executeBFS();
            } else if (dijkstraButton.isSelected()) {
                executeDijkstra();
            } else if (jpsButton.isSelected()) {
                executeJPS();
            }
        }
    }

    private class CellMouseListener extends MouseAdapter {
        @Override
        public void mousePressed(MouseEvent e) {
            Cell cell = (Cell) e.getSource();
            if (!cell.isStart && !cell.isEnd) {
                if (SwingUtilities.isLeftMouseButton(e)) {
                    cell.setObstacle();
                } else if (SwingUtilities.isRightMouseButton(e)) {
                    cell.reset();
                }
            }
        }

        @Override
        public void mouseEntered(MouseEvent e) {
            if (isSettingObstacles) {
                Cell cell = (Cell) e.getSource();
                if (!cell.isStart && !cell.isEnd) {
                    cell.setObstacle();
                }
            }
        }
    }

    // A*算法实现
    private void executeAStar() {
        new Thread(() -> {
            // 实现A*算法
            PriorityQueue<Node> openSet = new PriorityQueue<>(Comparator.comparingInt(n -> n.fCost));
            Map<Point, Node> allNodes = new HashMap<>();

            Node startNode = new Node(start.x, start.y);
            startNode.gCost = 0;
            startNode.hCost = calculateDistance(start, end);
            startNode.fCost = startNode.hCost;
            openSet.add(startNode);
            allNodes.put(new Point(start.x, start.y), startNode);

            while (!openSet.isEmpty()) {
                Node currentNode = openSet.poll();

                // 如果到达终点
                if (currentNode.x == end.x && currentNode.y == end.y) {
                    // 回溯路径
                    retracePath(currentNode);
                    return;
                }

                // 标记为已访问
                if (!(currentNode.x == start.x && currentNode.y == start.y)) {
                    final int x = currentNode.x;
                    final int y = currentNode.y;
                    SwingUtilities.invokeLater(() -> grid[x][y].setVisited());
                    try {
                        Thread.sleep(20);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }

                // 检查所有邻居
                for (int i = -1; i <= 1; i++) {
                    for (int j = -1; j <= 1; j++) {
                        if (i == 0 && j == 0) continue; // 跳过自身

                        int checkX = currentNode.x + i;
                        int checkY = currentNode.y + j;

                        // 检查边界
                        if (checkX < 0 || checkX >= GRID_SIZE || checkY < 0 || checkY >= GRID_SIZE) {
                            continue;
                        }

                        // 检查障碍物
                        if (grid[checkX][checkY].isObstacle) {
                            continue;
                        }

                        Point neighborPoint = new Point(checkX, checkY);
                        Node neighborNode = allNodes.getOrDefault(neighborPoint, new Node(checkX, checkY));

                        int newMovementCostToNeighbor = currentNode.gCost + calculateDistance(
                                new Point(currentNode.x, currentNode.y), neighborPoint);

                        if (newMovementCostToNeighbor < neighborNode.gCost || !allNodes.containsKey(neighborPoint)) {
                            neighborNode.gCost = newMovementCostToNeighbor;
                            neighborNode.hCost = calculateDistance(neighborPoint, end);
                            neighborNode.fCost = neighborNode.gCost + neighborNode.hCost;
                            neighborNode.parent = currentNode;

                            if (!allNodes.containsKey(neighborPoint)) {
                                openSet.add(neighborNode);
                                allNodes.put(neighborPoint, neighborNode);
                            }
                        }
                    }
                }
            }

            // 如果没有找到路径
            JOptionPane.showMessageDialog(this, "找不到从起点到终点的路径！");
        }).start();
    }

    // 计算两点之间的曼哈顿距离
    private int calculateDistance(Point a, Point b) {
        return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
    }

    // 回溯并显示路径
    private void retracePath(Node endNode) {
        List<Node> path = new ArrayList<>();
        Node currentNode = endNode;

        while (currentNode != null) {
            path.add(currentNode);
            currentNode = currentNode.parent;
        }

        Collections.reverse(path);

        // 显示路径
        for (Node node : path) {
            if (!(node.x == start.x && node.y == start.y) && !(node.x == end.x && node.y == end.y)) {
                final int x = node.x;
                final int y = node.y;
                SwingUtilities.invokeLater(() -> grid[x][y].setPath());
                try {
                    Thread.sleep(50);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        }
    }

    private void executeBFS() {
        // 这里实现BFS算法
        new Thread(() -> {
            Queue<Point> queue = new LinkedList<>();
            Map<Point, Point> parentMap = new HashMap<>();
            boolean[][] visited = new boolean[GRID_SIZE][GRID_SIZE];

            queue.add(start);
            visited[start.x][start.y] = true;

            int[] dx = {-1, 1, 0, 0};
            int[] dy = {0, 0, -1, 1};

            while (!queue.isEmpty()) {
                Point current = queue.poll();

                // 如果到达终点
                if (current.equals(end)) {
                    // 回溯路径
                    retraceBFSPath(parentMap);
                    return;
                }

                // 标记为已访问
                if (!current.equals(start)) {
                    final int x = current.x;
                    final int y = current.y;
                    SwingUtilities.invokeLater(() -> grid[x][y].setVisited());
                    try {
                        Thread.sleep(20);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }

                // 检查所有邻居
                for (int i = 0; i < 4; i++) {
                    int nx = current.x + dx[i];
                    int ny = current.y + dy[i];

                    // 检查边界
                    if (nx < 0 || nx >= GRID_SIZE || ny < 0 || ny >= GRID_SIZE) {
                        continue;
                    }

                    // 检查障碍物和是否已访问
                    if (!grid[nx][ny].isObstacle && !visited[nx][ny]) {
                        Point neighbor = new Point(nx, ny);
                        queue.add(neighbor);
                        visited[nx][ny] = true;
                        parentMap.put(neighbor, current);
                    }
                }
            }

            // 如果没有找到路径
            JOptionPane.showMessageDialog(this, "找不到从起点到终点的路径！");
        }).start();
    }

    private void retraceBFSPath(Map<Point, Point> parentMap) {
        List<Point> path = new ArrayList<>();
        Point current = end;

        while (!current.equals(start)) {
            path.add(current);
            current = parentMap.get(current);
        }

        Collections.reverse(path);

        // 显示路径
        for (Point point : path) {
            if (!point.equals(start) && !point.equals(end)) {
                final int x = point.x;
                final int y = point.y;
                SwingUtilities.invokeLater(() -> grid[x][y].setPath());
                try {
                    Thread.sleep(50);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        }
    }

    private void executeDijkstra() {
        new Thread(() -> {
            // 实现A*算法
            PriorityQueue<Node> openSet = new PriorityQueue<>(Comparator.comparingInt(n -> n.fCost));
            Map<Point, Node> allNodes = new HashMap<>();

            Node startNode = new Node(start.x, start.y);
            startNode.gCost = 0;
            startNode.hCost = 0;
            startNode.fCost = startNode.hCost;
            openSet.add(startNode);
            allNodes.put(new Point(start.x, start.y), startNode);

            while (!openSet.isEmpty()) {
                Node currentNode = openSet.poll();

                // 如果到达终点
                if (currentNode.x == end.x && currentNode.y == end.y) {
                    // 回溯路径
                    retracePath(currentNode);
                    return;
                }

                // 标记为已访问
                if (!(currentNode.x == start.x && currentNode.y == start.y)) {
                    final int x = currentNode.x;
                    final int y = currentNode.y;
                    SwingUtilities.invokeLater(() -> grid[x][y].setVisited());
                    try {
                        Thread.sleep(20);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }

                // 检查所有邻居
                for (int i = -1; i <= 1; i++) {
                    for (int j = -1; j <= 1; j++) {
                        if (i == 0 && j == 0) continue; // 跳过自身

                        int checkX = currentNode.x + i;
                        int checkY = currentNode.y + j;

                        // 检查边界
                        if (checkX < 0 || checkX >= GRID_SIZE || checkY < 0 || checkY >= GRID_SIZE) {
                            continue;
                        }

                        // 检查障碍物
                        if (grid[checkX][checkY].isObstacle) {
                            continue;
                        }

                        Point neighborPoint = new Point(checkX, checkY);
                        Node neighborNode = allNodes.getOrDefault(neighborPoint, new Node(checkX, checkY));

                        int newMovementCostToNeighbor = currentNode.gCost + calculateDistance(
                                new Point(currentNode.x, currentNode.y), neighborPoint);

                        if (newMovementCostToNeighbor < neighborNode.gCost || !allNodes.containsKey(neighborPoint)) {
                            neighborNode.gCost = newMovementCostToNeighbor;
                            neighborNode.hCost = calculateDistance(neighborPoint, end);
                            neighborNode.fCost = neighborNode.gCost + neighborNode.hCost;
                            neighborNode.parent = currentNode;

                            if (!allNodes.containsKey(neighborPoint)) {
                                openSet.add(neighborNode);
                                allNodes.put(neighborPoint, neighborNode);
                            }
                        }
                    }
                }
            }

            // 如果没有找到路径
            JOptionPane.showMessageDialog(this, "找不到从起点到终点的路径！");
        }).start();
    }

    private void executeJPS() {
        // JPS算法实现较为复杂，这里简化处理
    }

    // 网格单元格类
    private class Cell extends JPanel {
        private int row, col;
        private boolean isStart = false;
        private boolean isEnd = false;
        private boolean isObstacle = false;
        private boolean isVisited = false;
        private boolean isPath = false;

        public Cell(int row, int col) {
            this.row = row;
            this.col = col;
            setPreferredSize(new Dimension(CELL_SIZE, CELL_SIZE));
            setBorder(BorderFactory.createLineBorder(Color.GRAY));
            setBackground(Color.WHITE);
        }

        public void setStart() {
            isStart = true;
            setBackground(Color.GREEN);
        }

        public void setEnd() {
            isEnd = true;
            setBackground(Color.RED);
        }

        public void setObstacle() {
            isObstacle = true;
            setBackground(Color.BLACK);
        }

        public void setVisited() {
            if (!isStart && !isEnd && !isObstacle) {
                isVisited = true;
                setBackground(Color.CYAN);
            }
        }

        public void setPath() {
            if (!isStart && !isEnd && !isObstacle) {
                isPath = true;
                setBackground(Color.YELLOW);
            }
        }

        public void reset() {
            isStart = false;
            isEnd = false;
            isObstacle = false;
            isVisited = false;
            isPath = false;
            setBackground(Color.WHITE);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
        }
    }

    // 节点类用于A*算法
    private class Node {
        int x, y;
        int gCost = Integer.MAX_VALUE;
        int hCost;
        int fCost = Integer.MAX_VALUE;
        Node parent;

        public Node(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(PathfindingVisualizer::new);
    }
}